package xyz.thoughtset.viewer.modules.api.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.PostConstruct;
import lombok.SneakyThrows;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.util.StringUtils;
import xyz.thoughtset.viewer.common.core.constants.StatusCodeConstant;
import xyz.thoughtset.viewer.common.crud.core.service.BaseServiceImpl;
import xyz.thoughtset.viewer.modules.api.dao.ApiInfoDao;
import xyz.thoughtset.viewer.modules.api.dao.ApiParamDao;
import xyz.thoughtset.viewer.modules.api.entity.ApiInfo;
import xyz.thoughtset.viewer.modules.api.entity.ApiParam;
import xyz.thoughtset.viewer.modules.datarel.service.DataRelService;
import xyz.thoughtset.viewer.modules.step.entity.QueryBlock;
import xyz.thoughtset.viewer.modules.step.service.QueryBlockService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.io.Serializable;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class ApiInfoServiceImpl extends BaseServiceImpl<ApiInfoDao, ApiInfo> implements ApiInfoService {
    @Autowired
    private ApiParamDao apiParamDao;
    @Autowired
    private QueryBlockService queryBlockService;
    @Autowired
    private DynamicApiService dynamicApiService;
    @Autowired
    private DataRelService dataRelService;

    @Override
    public ApiInfo saveData(ApiInfo entity) {
        if(ObjectUtils.isEmpty(entity.getQueryType())) {
            entity.setQueryType(0);
        }
        if(entity.getQueryType()>10){
            entity.setStatesCode(StatusCodeConstant.EDITING);
            if (!StringUtils.hasText(entity.getUrl())) throw new RuntimeException("URL WAS NULL");
        }
        if (checkUnique(entity)){
            throw new RuntimeException("url was been used");
        }
        if (checkNoWorking(entity)){
            throw new RuntimeException("entity was working");
        }
        saveOrUpdate(entity);
        List<ApiParam> apiParams = entity.getApiParams();
        if (!ObjectUtils.isEmpty(apiParams)){
            QueryWrapper<ApiParam> paramQuery = new QueryWrapper();
            paramQuery.lambda().eq(ApiParam::getPid,entity.getId()).select(ApiParam::getId);
            List<ApiParam> oldParams = apiParamDao.selectList(paramQuery);
            HashSet params = new HashSet<>();
            for (ApiParam param : apiParams){
                param.setPid(entity.getId());
                apiParamDao.insertOrUpdate(param);
                params.add(param.getId());
            }
            if (!ObjectUtils.isEmpty(oldParams)){
                List<String> delIds = oldParams.stream()
                        .filter(e->!params.contains(e.getId()))
                        .map(ApiParam::getId)  // 提取name属性
                        .collect(Collectors.toList());
                apiParamDao.deleteByIds(delIds);
            }
        }
        dataRelService.saveRels(entity.getId(),entity.getDataRels());
        return entity;
    }

    @Override
    public ApiInfo getById(Serializable id) {
        ApiInfo result = super.getById(id);
        fillObj(result);
        return result;
    }

    private ApiInfo fillObj(ApiInfo apiInfo) {
        String pkey = apiInfo.getId();
        QueryWrapper<ApiParam> query = new QueryWrapper();
        query.lambda().eq(ApiParam::getPid,pkey).orderByAsc(ApiParam::getOrderNum).orderByDesc(ApiParam::getUpdatedAt);
        apiInfo.setApiParams(apiParamDao.selectList(query));
        apiInfo.setDataRels(dataRelService.listByPId(pkey));
        return apiInfo;
    }

    @Override
    public boolean deleteById(String pkey) {
        if (dynamicApiService.checkHasWorking(pkey)){
            throw new RuntimeException("正在使用中请先停止再删除");
        }
        List<QueryBlock> blocks = queryBlockService.listByPId(pkey);
        if (!ObjectUtils.isEmpty(blocks)) {
            for (QueryBlock block : blocks){
                queryBlockService.deleteById(block.getId());
            }
        }
        QueryWrapper<ApiParam> query = this.pidQueryWrapper(pkey);
        apiParamDao.delete(query);
        dataRelService.delRelsByPId(pkey);
        return super.deleteById(pkey);
    }

    @Override
    public boolean checkUnique(ApiInfo entity) {
        String url = entity.getUrl();
        if (StringUtils.hasText(url)) return false;
        QueryWrapper<ApiInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(ApiInfo::getUrl, url);
        if (StringUtils.hasText(entity.getId())) {
            queryWrapper.lambda().ne(ApiInfo::getId, entity.getId());
        }
        return this.count(queryWrapper) == 0;
    }

    @Override
    public boolean checkNoWorking(ApiInfo entity) {
        QueryWrapper<ApiInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
                .eq(ApiInfo::getId, entity.getId())
                .eq(ApiInfo::getStatesCode, StatusCodeConstant.RUNNING);
        return this.count(queryWrapper) > 0;
    }


    @SneakyThrows
    @Override
    public void publishApi(String id) {
        ApiInfo apiInfo = getById(id);
        baseMapper.updateById(new ApiInfo(id, StatusCodeConstant.RUNNING));
        if(apiInfo.getQueryType()>10){
            dynamicApiService.registerMapping(apiInfo);
            apiInfo.groupRels();
        }
    }

    @Override
    @SneakyThrows
    public void unpublishedApi(String id) {
//        dynamicApiService.unregisterMapping(super.getById(id));
        baseMapper.updateById(new ApiInfo(id, StatusCodeConstant.EDITING));
        dynamicApiService.unregisterMapping(id);
    }

    @PostConstruct
    public void initData() {
        // 初始化时加载所有API
        QueryWrapper<ApiInfo> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda()
//                .select(ApiInfo::getId, ApiInfo::getUrl, ApiInfo::getStatesCode)
                .eq(ApiInfo::getStatesCode, 200)
                .isNotNull(ApiInfo::getQueryType)
                .ge(ApiInfo::getQueryType,10); // 仅加载发布状态的API
        List<ApiInfo> apiInfos = this.list(queryWrapper);
        apiInfos.parallelStream()
                .forEach(apiInfo -> {
                    try {
                        dynamicApiService.registerMapping(apiInfo);
                        fillObj(apiInfo);
                        apiInfo.groupRels();
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                });
    }
}
